Dentro del DOM tenemos dos tipos de nodo: los elementos HTML, que se corresponden con las etiquetas HTML que estamos usando en el documento; y los nodos de texto, que hacen referencia al texto contenido en cada nodo elemento.
Los elementos son los nodos principales de JS, porque contienen todos los atributos y propiedades disponibles para ese elemento en HTML, que también podrán ser modificadas vía JavaScript. Los nodos de texto simplemente contienen el texto del elemento y no permiten tantas opciones de manipulación por JS.
Hasta ahora hemos visto como trabajar con el texto de un nodo mediante su propiedad textContent. Y de forma indirecta, también hemos añadido nodos a un elemento mediante la propiedad innerHTML. Lo vemos en el siguiente ejemplo:
let numero = 0;
function sumaLista() {
let lista = document.getElementById('lista').innerHTML;
numero = numero + 1;
lista += '<li>Elemento de lista ' + numero + '</li>';
document.getElementById('lista').innerHTML = lista;
}
Otra forma de añadir contenido al documento es creando desde cero en JS el nodo a insertar, darle contenido y propiedades, y añadirlo en el punto deseado del documento.
Este es un método del documento que crea directamente un nodo de texto, algo así como el textContent, pero independiente de cualquier nodo. Una vez creado lo podemos añadir a cualquier nodo elemento del documento.
let texto = document.createTextNode('Esto es un párrafo');
Este otro método del documento genera de forma dinámica cualquier elemento HTML que pasemos como parámetro. Igual que ocurre con el caso anterior, el elemento queda disponible en la memoria del programa para ser añadido al DOM en cualquier momento.
Con esta instrucción creamos un elemento tipo párrafo: let parrafo = document.createElement('p');
Y con esta otra un elemento tipo li: let lista = document.createElement('li');
Una vez creados los nodos, tenemos que insertarlos en su ubicación, y esta puede ser otro nodo creado en el programa, o un nodo existente en el documento (una etiqueta HTML). Para eso tenemos varios métodos del documento, aunque el más directo y completo es el método append().
Para añadir nuestro nodo de texto como contenido al nodo de tipo li, tenemos que "hacer un append" sobre el nodo li con el texto, de la siguiente forma: lista.append(texto)
Y si queremos añadir el nodo lista (con su texto ya incorporado) a un ul del documento con id="mi_listado", haremos esto: document.getElementById('mi_listado').append(lista)
Una vez creado el nodo podemos completar su contenido y funcionalidad añadiendole los atributos necesarios (class, id, title, href...). Para ello usamos el método nodo.setAttribute('nombre_atributo', 'valor_del_atributo')
Para añadir la clase "lista" al elemento li creado de forma dinámica haríamos esto: lista.setAttribute('class','lista')
function creaLista() {
//crea un nodo de texto
let texto = document.createTextNode('Elemento creado dinámicamente');
//crea un nodo tipo li
let lista = document.createElement('li');
//defino atributos
lista.setAttribute('class', 'lista');
//primero paso el texto a la lista
lista.append(texto);
//ahora paso la lista al ul del documento donde lo quiero mostrar
document.getElementById('mi_listado').append(lista);
}
El método append() inserta un nuevo nodo al final de la lista de nodos que contiene el elemento en el que hacemos la inserción. No elimina el contenido previo que pueda haber en el contenedor. En ese sentido, su funcionamiento es idéntico al método appendChild(), que hace exáctamente lo mismo.
Las diferencias entre estos dos métodos están en que appendChild() sólo admite un único nodo como argumento, y este tiene que ser nodo de tipo elemento necesariamente, es decir, no admite nodos de tipo texto como elementos a insertar. En cambio append() sí admite varios nodos a la vez como argumentos, y sí admite nodos de texto. Es por esto que preferimos usar este método respecto al otro.
Esta expersión es perfectamente válida: document.querySelector('#intro').append(nodo1, nodo2, 'texto como nodo de texto', nodo3)
En cambio el método appendChild() sólo permite: document.querySelector('#intro').appendChild(nodo)
Este método se comporta de la misma forma que append(), pero en lugar de insertar al final de la lista de nodos del contenedor, inserta sus argumentos, al principio de la lista de nodos del contenedor, delante de cualquier elemento ya existente. Y de la misma forma que append(), admite varios nodos y nodos de texto de forma simultánea como argumentos.
document.querySelector('#intro').prepend(nodo1, nodo2, 'texto como nodo de texto', nodo3)
Ambos métodos permiten insertar nodos delante de un nodo existente. Y existente en todos estos casos que estamos viendo significa tanto que existe en el DOM como que es un elemento del script que todavía no está en el DOM (por ejemplo creado con el método document.createElement()).
Pero el primer caso es un método que se aplica directamente sobre el nodo que va a quedar detrás del elemento que vamos a insertar en la lista de nodos. Por ejemplo:
let parrafo = document.createElement('p');
let titulo = document.createElement('h2');
p.before(titulo)
Devolverá esta salida:
<h3></h3><p></p>
Y en el segundo caso, insertBefore() se aplica desde el elemento contenedor donde vamos a insertar el nodo, y además es un método que requiere un segundo argumento que indique el nodo delante del cual queremos insertar el nuevo nodo.
Su estructura sería: nodocontenedor.insertBefore(nuevo_nodo, nodo_de_referencia)
El segundo argumento es obligatorio, pero si no tenemos un nodo de referencia podemos usar la expresión null que colocará al nuevo nodo al final de la lista de nodos del contenedor.
Partiendo de este HTML
<div class="caja">
<p class="parrafo"></p>
</div>
El siguiente código
let parrafo = document.querySelector('.parrafo');
let h3 = document.createElement('h3');
let contenedor = parrafo.parentNode;
contenedor.insertBefore(h3, parrafo);
Nos devolverá
<div class="caja">
<h3><h3>
<p class="parrafo"></p>
</div>
El método after() inserta un nuevo nodo a continuación del nodo al que aplicamos el método. Es idéntico a before(), pero en este caso inserta después en lugar de antes.
Como nota, decir que no existe un método insertAfter(), pero su cometido se puede conseguir con la combinación de los métodos ya existentes.
Este método permite reemplazar un nodo existente por otro:
let div = document.createElement("div");
let p = document.createElement("p");
div.appendChild(p);
let span = document.createElement("span");
p.replaceWith(span);
Devolverá:<div><span></span></div>
De la misma forma que para añadir contenido podemos optar por la opción de modificar directamente el texto del elemento, o trabajar con los métodos de los nodos de JavaScript, podemos usar esas dos opciones para eliminar contenido del DOM.
En este caso tenemos que modificar el html del documento eliminado las etiquetas correspondientes de los nodos a suprimir. Por ejemplo, al pulsar el siguiente botón vamos a eliminar el contenido de la lista adjunta:
Partiendo de este HTML
function eliminaHtml() {
document.getElementById('lista_eliminar').innerHTML = '';
}
Para eliminar un nodo desde JavaScript necesitamos el método remove(), que es un método disponible para otros nodos y para el documento. O el método removeChild(nodo), que está disponible para cualquier nodo que tenga elementos anidados. En el primer caso, la acción de eliminar puede darse sobre el propio nodo directamente, o desde un nodo que guarde relación con el nodo a eliminar (como un nodo adyacente). En el segundo caso partimos desde el elemento parent del propio nodo a eliminar (su contenedor directo) e identificamos el elemento a eliminar dentro de los paréntesis del método removeChild().
en este caso solo identificamos el nodo a eliminar, y le aplicamos directamente el método remove()
Este párrafo tiene un id que usamos para identificarlo en JS y aplicarle el método remove().
function eliminaDirecto() {
document.getElementById('elimina_p').remove();
}
Este es el párrafo 1
Este es el párrafo 2
function eliminaHermano() {
document.getElementById('parr_a').nextElementSibling.remove();
}
En este caso el método no es exactamente el mismo, sino que usamos removeChild(elemento_anidado_a_eliminar). Donde partiendo del elemento contenedor, le aplicamos este método, indicando entre paréntesis cual de los elementos anidados eliminamos.
function eliminaHijo() {
let listado = document.getElementById('lista_nodos');
let posicion = document.getElementById('ident_elem').value;
posicion = parseInt(posicion);
let elemento = listado.children[posicion];
listado.removeChild(elemento);
}